﻿using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;

// ReSharper disable once CheckNamespace
// 限定为System，从而减少引用
namespace System
{
    public static class ObjectExtension
    {
        /// <summary>
        /// 在对象不为空的情况下执行一次操作
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="objectT"></param>
        /// <param name="action"></param>
        public static void IfNotNull<T>(this T objectT, Action<T> action)
        {
            if (objectT != null)
                action(objectT);
        }

        /// <summary>
        /// 安全的属性访问操作，当引用为空时，返回一个默认值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="objectT"></param>
        /// <param name="selector"></param>
        /// <returns></returns>
        public static TValue IfNotNull<T, TValue>(this T objectT, Func<T, TValue> selector)
        {
            return objectT == null ? default(TValue) : selector(objectT);
        }

        /// <summary>
        /// 安全的属性访问操作，当引用为空时，返回一个指定的默认值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="objectT"></param>
        /// <param name="selector"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static TValue IfNotNull<T, TValue>(this T objectT, Func<T, TValue> selector, TValue defaultValue)
        {
            return objectT == null ? defaultValue : selector(objectT);
        }

        /// <summary>
        /// 安全的转型，当被转型对象为null时，返回一个默认的目标类型的实例
        /// </summary>
        /// <typeparam name="TT"></typeparam>
        /// <param name="target"></param>
        /// <returns></returns>
        public static TT As<TT>(this object target) where TT : class
        {
            return target.IfNotNull(i => i as TT);
        } 

        /// <summary>
        /// 读取指定的成员的名称
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TP"></typeparam>
        /// <param name="source"></param>
        /// <param name="memberSelector"></param>
        /// <returns></returns>
        public static string ReadMemberName<T, TP>(this T source, Expression<Func<T, TP>> memberSelector)
        {
            //NOTE，主要是成员访问表达式，在某先情况下外层可能是个一元表达式（转型）
            return memberSelector.Body.As<MemberExpression>().IfNotNull(i => i.Member.Name)
                   ?? memberSelector.Body.As<UnaryExpression>()
                       .IfNotNull(i => i.Operand.As<MemberExpression>().IfNotNull(u => u.Member.Name));
        }
    }
}